package com.scs.application.modules.design.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Maps;
import com.scs.application.core.exceptions.BusinessException;
import com.scs.application.core.utils.StringUtils;
import com.scs.application.modules.design.constDir.OrderRule;
import com.scs.application.modules.design.constDir.QueryRule;
import com.scs.application.modules.design.dto.OrderCondition;
import com.scs.application.modules.design.dto.QueryCondition;
import lombok.extern.slf4j.Slf4j;

import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;

/**
 * @description:
 */
@Slf4j
public class QueryGenerator {

    public static final String REQ_QUERY_CONDITIONS_NAME = "queryString";
    public static final String REQ_ORDER_CONDITIONS_NAME = "orderString";

    public static final String REQ_PAGE_SIZE_NAME = "rowsPerPage";
    public static final String REQ_CURRENT_PAGE_NAME = "currentPage";


    /**
     * 从请求参数中获取查询条件及排序条件 {@link #REQ_ORDER_CONDITIONS_NAME}、{@link #REQ_ORDER_CONDITIONS_NAME}
     *
     * @param request
     * @return
     */
    public static QueryWrapper initQueryWrapper(HttpServletRequest request) {

        List<QueryCondition> queryConditions = parseQueryConditions(request);
        List<OrderCondition> orderConditions = parseOrderConditions(request);

        return initQueryWrapper(queryConditions, orderConditions);
    }

    /**
     * @return
     */
    public static QueryWrapper initQueryWrapper(String queryConditionsStr,String orderConditionsStr) {

        List<QueryCondition> queryConditions = null;

        if (StringUtils.isNotBlank(queryConditionsStr)) {
            try {
                queryConditions = JSON.parseArray(queryConditionsStr, QueryCondition.class);
            } catch (Exception e) {
                throw new BusinessException("查询条件构造失败，可能是格式不正确", e);
            }
        }

        List<OrderCondition> orderConditions = null;
        if (StringUtils.isNotBlank(orderConditionsStr)) {
            try {
                orderConditions = JSON.parseArray(orderConditionsStr, OrderCondition.class);
            } catch (Exception e) {
                log.error("排序条件构造失败，可能是格式不正确", e);
                orderConditions = Collections.emptyList();
            }
        }

        return initQueryWrapper(queryConditions, orderConditions);
    }


    public static List<QueryCondition> parseQueryConditions(HttpServletRequest request) {
        List<QueryCondition> queryConditions = null;
        String queryConditionsStr = request.getParameter(REQ_QUERY_CONDITIONS_NAME);

        if (StringUtils.isNotBlank(queryConditionsStr)) {
            try {
                queryConditions = JSON.parseArray(queryConditionsStr, QueryCondition.class);
            } catch (Exception e) {
                throw new BusinessException("查询条件构造失败，可能是格式不正确", e);
            }
        }
        return queryConditions;
    }

    public static List<OrderCondition> parseOrderConditions(HttpServletRequest request) {
        List<OrderCondition> orderConditions = null;
        String orderConditionsStr = request.getParameter(REQ_ORDER_CONDITIONS_NAME);
        if (StringUtils.isNotBlank(orderConditionsStr)) {
            try {
                orderConditions = JSON.parseArray(orderConditionsStr, OrderCondition.class);
            } catch (Exception e) {
                log.error("排序条件构造失败，可能是格式不正确", e);
                orderConditions = Collections.emptyList();
            }
        }
        return orderConditions;
    }

    public static QueryWrapper initQueryWrapper(List<QueryCondition> queryConditions) {
        return initQueryWrapper(queryConditions, Collections.emptyList());
    }

    public static QueryWrapper initQueryWrapper(List<QueryCondition> queryConditions, List<OrderCondition> orderConditions) {
        QueryWrapper wrapper = new QueryWrapper();

        if (queryConditions == null) {
            queryConditions = Collections.emptyList();
        }
        if (orderConditions == null) {
            orderConditions = Collections.emptyList();
        }
        String applySql = "";
        for (QueryCondition condition : queryConditions) {
            String rule = condition.getRule();
            Object val = condition.getVal();
            String field = condition.getField();
            String uncamelField = StringUtils.uncamelCase(field);

            if (val == null || StringUtils.isBlank(val.toString())) {
                continue;
            }

            val = StringUtils.boolParseToNumber(val);

            if (QueryRule.BETWEEN.getCondition().equalsIgnoreCase(rule)) {
                processBetweenRule(wrapper, val, uncamelField);
                continue;
            } else if (QueryRule.EQ.getCondition().equalsIgnoreCase(rule)) {
                wrapper.eq(uncamelField, val);
            } else if (QueryRule.NE.getCondition().equalsIgnoreCase(rule)) {
                wrapper.ne(uncamelField, val);
            } else if (QueryRule.LIKE_LEFT.getCondition().equalsIgnoreCase(rule)) {
                wrapper.likeLeft(uncamelField, val);
            } else if (QueryRule.LIKE_RIGHT.getCondition().equalsIgnoreCase(rule)) {
                wrapper.likeRight(uncamelField, val);
            } else if (QueryRule.LIKE.getCondition().equalsIgnoreCase(rule)) {
                wrapper.like(uncamelField, val);
            } else if (QueryRule.LT.getCondition().equalsIgnoreCase(rule)) {
                wrapper.lt(uncamelField, val);
            } else if (QueryRule.LE.getCondition().equalsIgnoreCase(rule)) {
                wrapper.le(uncamelField, val);
            } else if (QueryRule.GT.getCondition().equalsIgnoreCase(rule)) {
                wrapper.gt(uncamelField, val);
            } else if (QueryRule.GE.getCondition().equalsIgnoreCase(rule)) {
                wrapper.ge(uncamelField, val);
            } else if (QueryRule.IN.getCondition().equalsIgnoreCase(rule)) {
                if (val instanceof JSONArray){
                   List<String> listStr = ((JSONArray) val).toJavaList(String.class);
                    wrapper.in(uncamelField, StringUtils.get10FromBoolean(listStr));
                }else{
                    wrapper.in(uncamelField, val);
                }

            } else if (QueryRule.NOT_IN.getCondition().equalsIgnoreCase(rule)) {
                if (val instanceof JSONArray){
                    List<String> listStr = ((JSONArray) val).toJavaList(String.class);
                    wrapper.notIn(uncamelField, StringUtils.get10FromBoolean(listStr));
                }else{
                    wrapper.notIn(uncamelField, val);
                }
            } else if (QueryRule.IS_NULL.getCondition().equalsIgnoreCase(rule)) {
                wrapper.isNull(uncamelField);
            } else if (QueryRule.IS_NOT_NULL.getCondition().equalsIgnoreCase(rule)) {
                wrapper.isNotNull(uncamelField);
            } else if (QueryRule.NOT_IN_SQL.getCondition().equalsIgnoreCase(rule)) {
                wrapper.notInSql(uncamelField,val+"");
            }else if (QueryRule.NOT_LIKE_ALL.getCondition().equalsIgnoreCase(rule)) {
                wrapper.notLike(uncamelField,val);
            } else if (QueryRule.OR.getCondition().equalsIgnoreCase(rule)) {
                wrapper.or();
                wrapper.eq(uncamelField, val);
            } else if (QueryRule.ORLIKE.getCondition().equalsIgnoreCase(rule)) {
                applySql += String.format(" or %s like '%s%s%s' ", uncamelField, "%", val.toString().replaceAll("%", "%%").replaceAll("'", ""), "%");
            }else if (QueryRule.AND_OR_IN.getCondition().equalsIgnoreCase(rule)) { //并且或者in，格式： and (a=1 or a=2)
                JSONArray arr = JSONArray.parseArray(val+"");
                if (arr != null && arr.size() > 0) {
                    JSONObject ob;
                    QueryWrapper wrapperAndOr = Wrappers.query();
                    List<String> inVals,andSql= new ArrayList<String>();
//                    int applyIndex = 0;
                    String fileName;
                    String insql;
                    for(int i=0; i< arr.size() ; i ++){
                        ob = arr.getJSONObject(i);
                        if (ob.getJSONArray("_val") ==null || ob.getJSONArray("_val").size() < 1) continue;
                        //直接转换有问题
                        inVals = (ob.getJSONArray("_val")).toJavaList(String.class);
                        if (inVals == null || inVals.size() < 1) continue;
                        fileName = StringUtils.camelToUnderline(ob.getString("_field"), 1);

                        //查询不出来，后续再试
//                        if (applyIndex != 0) {
//                            wrapperAndOr.or();
//                        }
//                        wrapperAndOr.in(true,fileName,inVals);

                        andSql.add(fileName+" in('"+StringUtils.join(inVals,"','")+"') ");
                    }
                    if (andSql.size() > 0) {
//                        wrapper.and(wrap -> wrapperAndOr);
                        applySql+=("and ("+StringUtils.join(andSql," or ")+")");
                    }
                }
            }
        }
        if(StringUtils.isNotBlank(applySql)) {
            wrapper.apply("(" + applySql.substring(3) + ")");
        }

        for (OrderCondition condition : orderConditions) {
            String orderField = StringUtils.uncamelCase(condition.getField());
            if (OrderRule.ASC.getCondition().equalsIgnoreCase(condition.getRule())) {
                wrapper.orderByAsc(orderField);
            } else if (OrderRule.DESC.getCondition().equalsIgnoreCase(condition.getRule())) {
                wrapper.orderByDesc(orderField);
            } else {
                wrapper.orderByAsc(orderField);
            }
        }

        return wrapper;
    }

    /**
     * 根据查询条件，解析为查询参数Map对象
     *
     * @param queryConditions
     * @return
     */
    public static Map<String, Object> parseParams(List<QueryCondition> queryConditions) {
        if (queryConditions == null) {
            return Maps.newHashMap();
        }

        Map<String, Integer> fieldMap = Maps.newHashMapWithExpectedSize(queryConditions.size());
        for (QueryCondition condition : queryConditions) {
            String field = condition.getField();
            Integer count = fieldMap.get(field);

            if (count == null) {
                count = 1;
            } else {
                count++;
            }
            fieldMap.put(field, count);
        }

        Map<String, Object> params = Maps.newHashMapWithExpectedSize(queryConditions.size());
        for (QueryCondition condition : queryConditions) {
            Object val = condition.getVal();
            String field = condition.getField();
            if (QueryRule.BETWEEN.getCondition().equalsIgnoreCase(condition.getRule())) {
                // 区间需要做特别处理
                if (val == null || (!val.getClass().isArray() && val.getClass() != JSONArray.class)) {
                    continue;
                }
                Object[] values = new Object[]{};
                if (val.getClass().isArray()) {
                    values = (Object[]) val;
                } else if (val.getClass() == JSONArray.class) {
                    values = ((JSONArray) val).toArray();
                }
                if (values.length == 0) {
                    params.put(field, new Object[]{null, null});
                } else if (values.length == 1) {
                    params.put(field, new Object[]{values[0], null});
                } else {
                    params.put(field, new Object[]{values[0], values[1]});
                }
                continue;
            }

            // 当一个字段出现多次时，字段后添加规则以进行区分
            if (fieldMap.get(field) > 1) {
                params.put(field + "_" + condition.getRule(), val);
            } else {
                params.put(field, val);
            }
        }
        return params;
    }

    /**
     * 从请求中获取分页参数，如果没有获取到，则默认为第一页、每页10条
     *
     * @param request
     * @return
     */
    public static Page parsePage(HttpServletRequest request) {
        String currentPageStr = request.getParameter(REQ_CURRENT_PAGE_NAME);
        String pageSizeStr = request.getParameter(REQ_PAGE_SIZE_NAME);

        int currentPage = 1;
        if (StringUtils.isNotBlank(currentPageStr) && StringUtils.isNumeric(currentPageStr)) {
            currentPage = Integer.parseInt(currentPageStr);
            currentPage = currentPage <= 0 ? 1 : currentPage;
        }

        int pageSize = 10;
        if (StringUtils.isNotBlank(pageSizeStr) && StringUtils.isNumeric(pageSizeStr)) {
            pageSize = Integer.parseInt(pageSizeStr);
            pageSize = pageSize <= 0 ? 10 : pageSize;
        } else if ("-1".equals(pageSizeStr)) { // -1时查全量
            pageSize = -1;
        }
        return new Page(currentPage, pageSize);
    }

    /**
     * 处理区间规则条件
     *
     * @param wrapper
     * @param val
     * @param uncamelField
     */
    private static void processBetweenRule(QueryWrapper wrapper, Object val, String uncamelField) {
        if (!val.getClass().isArray() && val.getClass() != JSONArray.class) {
            return;
        }
        Object[] values = new Object[]{};
        if (val.getClass().isArray()) {
            values = (Object[]) val;
        } else if (val.getClass() == JSONArray.class) {
            values = ((JSONArray) val).toArray();
        }

        if (values.length != 2) {
            return;
        }
        if(values[0] == null && values[1] == null){
            return;
        }

        if (StringUtils.isBlank(values[0].toString()) && StringUtils.isBlank(values[1].toString())) {
            return;
        }else if (values.length == 2 ) {
            wrapper.between(uncamelField, values[0], values[1]);
        } else if (values.length ==1 && StringUtils.isNotBlank(values[0].toString())  ) {
            wrapper.ge(uncamelField, values[0]);
        } else if (values.length ==1 && StringUtils.isNotBlank(values[1].toString())) {
            wrapper.le(uncamelField, values[1]);
        }
    }

    /**
    * @Description： 获取queryString的 sql查询条件
     * @return field =1 and field = 2
    */
    public static String getSqlWhere(String queryString) {
        if (StringUtils.isBlank(queryString)) return null;
        List<QueryCondition> queryConditions = JSON.parseArray(queryString, QueryCondition.class);
        List<String> sqlWhere = new ArrayList<String>();

        for (QueryCondition condition : queryConditions) {
            String rule = condition.getRule();
            Object val = condition.getVal();
            String field = condition.getField();
            String uncamelField = StringUtils.uncamelCase(field);
            if (val == null || StringUtils.isBlank(val.toString())) {
                continue;
            }

            if (QueryRule.EQ.getCondition().equalsIgnoreCase(rule)) {
                sqlWhere.add(uncamelField+" = '"+val+"'");
            } else if (QueryRule.NE.getCondition().equalsIgnoreCase(rule)) {
                sqlWhere.add(uncamelField+" != '"+val+"'");
            } else if (QueryRule.LIKE_LEFT.getCondition().equalsIgnoreCase(rule)) {
                sqlWhere.add(uncamelField+" != '"+val+"'");
            } else if (QueryRule.LIKE.getCondition().equalsIgnoreCase(rule)) {
                sqlWhere.add(uncamelField+" like '%"+val+"%'");
            }
        }

        return StringUtils.join(sqlWhere," and ");
    }


}
